package cn.iocoder.yudao.module.ad.framework.core.channel.impl;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.ad.api.advertiser.dto.AdvertiserRespDTO;
import cn.iocoder.yudao.module.ad.framework.core.channel.AdChannelClient;
import cn.iocoder.yudao.module.ad.api.channel.dto.ClueSyncReqDTO;
import cn.iocoder.yudao.module.ad.api.channel.dto.ClueSyncRespDTO;
import cn.iocoder.yudao.module.ad.api.channel.dto.TokenGenRespDTO;
import cn.iocoder.yudao.module.ad.framework.core.enums.clue.AdActionTypeEnum;
import cn.iocoder.yudao.module.ad.framework.core.enums.clue.AdClueStatusEnum;
import cn.iocoder.yudao.module.ad.framework.core.enums.clue.AdClueTypeEnum;
import cn.iocoder.yudao.module.ad.framework.core.enums.clue.AdFollowStatusEnum;
import cn.iocoder.yudao.module.ad.framework.core.properties.AdChannelProperties;
import cn.iocoder.yudao.module.ad.framework.core.util.DouyinSignUtils;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
public class LkChannelClient extends AdChannelClient {


    private static final TimedCache<String, String> localTokenCache = CacheUtil.newTimedCache(1000);

    private static final String AUTH_REDIRECT_URI = "https://scrm-admin.jzsaas.com/open-api/ad/auth/token-redirect/douyin";
    private static final String CACHE_KEY = "LK_CHANNEL_TOKEN";

    private static final String CRM_API_KEY = "awe9d8mv3u2g970y";

    private static final String CRM_API_SECRET = "ccbb7820b6ad8c83c2eb79c0913f858d";

    private static final Integer CRM_SOURCE = 101;


    public LkChannelClient(AdChannelProperties properties) {
        super(properties);
    }

    /**
     * 逻辑上定义为每分钟执行一次， 查询开始和结束时间为， LastQueryTime - 1min, LastQueryTime; => LastQueryTime = now() - 10min;
     *
     * @param reqDTO
     * @return
     * @author PetePower
     * @since 2024-06-17
     */
    @Override
    public List<ClueSyncRespDTO> getClue(ClueSyncReqDTO reqDTO) {
        int pageIndex = reqDTO.getPageNo();
        int pageSize = 100;

        String accessToken = localTokenCache.get(CACHE_KEY + properties.getId());
        if (StrUtil.isEmpty(accessToken)) {
            accessToken = getAccessToken();
        }
        // 如果首次查询时， startTime是空的， 那么直接指定到今年第一天
        LocalDateTime startTime = DateUtil.beginOfYear(new Date()).toLocalDateTime();
        if (Objects.nonNull(reqDTO.getStartTime())) {
            startTime = reqDTO.getStartTime();
        }
        List<ClueSyncRespDTO> dataList = getDataList(
                pageIndex,
                pageSize,
                LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATETIME_FORMATTER),
                LocalDateTimeUtil.format(reqDTO.getEndTime(), DatePattern.NORM_DATETIME_FORMATTER),
                accessToken
        );

        return dataList;
    }

    @Override
    public String genAuthUrl() {
        // https://developers.e.kuaishou.com/tools/authorize
//        String url = "https://developers.e.kuaishou.com/tools/authorize";
//        Map<String, Object> params = new HashMap<>();
//        params.put("app_id", getApiKey());
//        params.put("scope", URLUtil.encode(ListUtil.toList("ad_query", "account_service", "ad_manage", "report_service").toString()));
//        params.put("redirect_uri", URLUtil.encode(AUTH_REDIRECT_URI));
//        params.put("oauth_type", "advertiser");
////        params.put("state", TenantContextHolder.getTenantId());
//        params.put("state", "TenantId:" + TenantContextHolder.getTenantId() + ",AccountId:" + properties.getId());
//        return StrUtil.concat(true, url, "?", HttpUtil.toParams(params, CharsetUtil.CHARSET_UTF_8, true));
        return null;
    }

    @Override
    public List<AdvertiserRespDTO> getAdvertiserList(String accessToken) {
        return null;
    }

    @Override
    public List<AdvertiserRespDTO> getAdvertiserAccountList(String accessToken, String advertiserId) {
        return null;
    }

    private List<ClueSyncRespDTO> getDataList(Integer pageNo, Integer pageSize, String startTime, String endTime, String accessToken) {
        String url = "https://open.douyin.com/goodlife/v1/open_api/crm/clue/query/";
        Map<String, Object> data = new HashMap<>();
        data.put("account_id", properties.getAccountId());
        data.put("end_time", endTime);
        data.put("page", pageNo);
        data.put("page_size", pageSize);
        data.put("start_time", startTime);
        HttpResponse httpResponse = HttpUtil.createGet(url + "?" + HttpUtil.toParams(data)).header(Header.CONTENT_TYPE, ContentType.JSON.getValue())
                .header("access-token", accessToken)
                .execute();
        String result = httpResponse.body();
        JSONObject jsonObject = JSONUtil.parseObj(result);
        JSONObject resultData = jsonObject.getJSONObject("data");
        // 先处理返回集合的转换
        List<ClueSyncRespDTO> resultDataList = new ArrayList<>();
        JSONArray jsonArray = resultData.getJSONArray("clue_data");
        if (ObjectUtil.notEqual(0, jsonObject.getJSONObject("extra").get("error_code"))) {
            return Collections.emptyList();
        }
        if (Objects.nonNull(jsonArray) && !jsonArray.isEmpty()) {
            jsonArray.forEach(jsonData -> {
                resultDataList.add(beanToResp(JSONUtil.parseObj(jsonData)));
            });
        }
//        if (Objects.nonNull(resultData.getJSONObject("page"))) {
//            // 再检查pageTotal 是否多页， 然后递归 getDataList
//            int pageTotal = resultData.getJSONObject("page").getInt("page_total");
//            if (pageTotal > pageNo) {
//                for (int i = pageNo + 1; i < pageTotal + 1; i ++ ) {
//                    resultDataList.addAll(getDataList(pageNo, pageSize, startTime, endTime, accessToken));
//                }
//            }
//        }

        return resultDataList;
    }

    private ClueSyncRespDTO beanToResp(JSONObject jsonObject) {
        // 相同字段或json驼峰直接toBean
        ClueSyncRespDTO resp = JSONUtil.toBean(jsonObject, ClueSyncRespDTO.class);
        resp.setCrmSource(CRM_SOURCE);
        // 线索来源转换
        resp.setActionType(actionTypeMapping(jsonObject.getInt("action_type")));
        // 客资组件类型转换
        resp.setClueType(clueTypeMapping(jsonObject.getInt("clue_type")));
        // 线索状态转换
        resp.setClueStatus(clueStatusMapping(jsonObject.getInt("effective_state")));
        // 跟进状态转换
        resp.setFollowStatus(followStatusMapping(jsonObject.getInt("follow_state_name")));
        // 流量类型
        resp.setFlowType(flowTypeMapping(jsonObject.getInt("flow_type")));

        // 原始线索id
        resp.setAdClueId(jsonObject.getStr("clue_id"));
        resp.setClueName(jsonObject.getStr("name"));

        DouyinSignUtils utils = new DouyinSignUtils(properties.getApiSecret());
        try {
            resp.setTelephone(utils.parsePhone(jsonObject.getStr("telephone")));
        } catch (Exception e) {
            resp.setTelephone("");
        }
        resp.setClueCreateTime(jsonObject.getStr("create_time_detail"));

        return resp;

    }

    /**
     * 跟进状态转换
     * @param follow_state_name
     * @since 2024-06-17
     * @author PetePower
     * 线索通话状态
     * 包含值：0-未联系,，-1-未接通，2-已接通，1-有效沟通，3-深度沟通
     * @return
     */
    private String followStatusMapping(Integer follow_state_name) {
        if (Objects.isNull(follow_state_name)) {
            return AdFollowStatusEnum.WAITING.getName();
        }
        switch (follow_state_name) {
            case 0:
                return AdFollowStatusEnum.WAITING.getName();
            case -1:
                return AdFollowStatusEnum.UN_CONNECT.getName();
            case 2:
                return AdFollowStatusEnum.CONNECT.getName();
            case 1:
                return AdFollowStatusEnum.INVALID.getName();
            case 3:
                return AdFollowStatusEnum.DEEP.getName();

        }
        return AdFollowStatusEnum.WAITING.getName();
    }

    /**
     * 流量类型转换
     * @param follow_state_name
     * @since 2024-06-17
     * @author PetePower
     * 线索通话状态
     * 包含值：0-未联系,，-1-未接通，2-已接通，1-有效沟通，3-深度沟通
     * @return
     */
    private String flowTypeMapping(Integer follow_state_name) {
        if (Objects.isNull(follow_state_name)) {
            return "未知";
        }
        switch (follow_state_name) {
            case 1:
                return "自然流量";
            case 2:
                return "广告流量";


        }
        return "未知";
    }

    /**
     * 线索来源枚举转换
     * @param actionType
     * @since 2024-06-17
     * @author PetePower
     * @return
     */
    private String actionTypeMapping(Integer actionType) {
        if (Objects.isNull(actionType)) {
            return AdActionTypeEnum.OTHER.getName();
        }
        switch (actionType) {
            case 1:
                return AdActionTypeEnum.SHORT_VIDEO.getName();
            case 2:
                return AdActionTypeEnum.LIVE.getName();
            case 3:
                return AdActionTypeEnum.MAIN_PAGE.getName();
            case 4:
                return AdActionTypeEnum.MESSAGE.getName();
            case 5:
                return AdActionTypeEnum.GROUP_PROMOTION.getName();
            case 6:
                return AdActionTypeEnum.STREAM.getName();
        }
        return AdActionTypeEnum.OTHER.getName();
    }

    /**
     * 线索状态枚举转换
     * @param clueStatus
     * @since 2024-06-17
     * @author PetePower
     * 线索状态值
     * 枚举值：1-新线索，2-有意向，3-转商机，4-无效，5-已加微信，7-待再次沟通
     * @return
     */
    private String clueStatusMapping(Integer clueStatus) {
        if (Objects.isNull(clueStatus)) {
            return AdClueStatusEnum.OTHER.getName();
        }
        switch (clueStatus) {
            case 1:
                return AdClueStatusEnum.NEW.getName();
            case 2:
                return AdClueStatusEnum.INTENTION.getName();
            case 3:
                return AdClueStatusEnum.BUSINESS.getName();
            case 4:
                return AdClueStatusEnum.INVALID.getName();
            case 5:
                return AdClueStatusEnum.CONTACT.getName();
            case 7:
                return AdClueStatusEnum.WAIT_NEXT_CONTACT.getName();
        }
        return AdClueStatusEnum.OTHER.getName();
    }

    /**
     * 留资组件枚举转换
     * @param clueType
     * @since 2024-06-17
     * @author PetePower
     * @return
     */
    private String clueTypeMapping(Integer clueType) {
        if (Objects.isNull(clueType)) {
            return AdClueTypeEnum.OTHER.getName();
        }
        switch (clueType) {
            case 0:
                return AdClueTypeEnum.FORM.getName();
            case 1:
                return AdClueTypeEnum.CHAT.getName();
            case 2:
                return AdClueTypeEnum.TEL.getName();
            case 7:
                return AdClueTypeEnum.GROUP_PROMOTION.getName();

        }
        return AdClueTypeEnum.OTHER.getName();
    }

    @Override
    public TokenGenRespDTO genToken(Map<String, String> params) {

        return null;
    }

    @Override
    public TokenGenRespDTO refreshToken(String accessToken, String refreshToken) {
        return null;
    }

    private String getAccessToken() {
        String url = "https://open.douyin.com/oauth/client_token/";
        Map<String, Object> data = new HashMap<>();
        data.put("client_key", properties.getApiKey());
        data.put("client_secret", properties.getApiSecret());
        data.put("grant_type", "client_credential");
        HttpResponse httpResponse = HttpUtil.createPost(url).header(Header.CONTENT_TYPE, ContentType.JSON.getValue())
                .body(JSONUtil.toJsonStr(data)).execute();
        ;
        String result = httpResponse.body();
        JSONObject jsonObject = JSONUtil.parseObj(result);
        String accessToken = jsonObject.getJSONObject("data").getStr("access_token");
        localTokenCache.put(CACHE_KEY + properties.getId(), accessToken, jsonObject.getJSONObject("data").getInt("expires_in"));
        return accessToken;
    }

    public String getApiKey() {
        if (properties.getAuthType() == 1) {
            return properties.getApiKey();
        } else {
            return CRM_API_KEY;
        }
    }

    public String getApiSecret() {
        if (properties.getAuthType() == 1) {
            return properties.getApiSecret();
        } else {
            return CRM_API_SECRET;
        }
    }
}
